home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / Unix / prefs_editor_gtk.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-02  |  34.2 KB  |  1,129 lines

  1. /*
  2.  *  prefs_editor_gtk.cpp - Preferences editor, Unix implementation using GTK+
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include "sysdeps.h"
  22.  
  23. #include <gtk/gtk.h>
  24. #include <stdlib.h>
  25. #include <dirent.h>
  26. #include <sys/socket.h>
  27. #include <sys/ioctl.h>
  28. #include <net/if.h>
  29. #include <net/if_arp.h>
  30.  
  31. #include "user_strings.h"
  32. #include "version.h"
  33. #include "cdrom.h"
  34. #include "xpram.h"
  35. #include "prefs.h"
  36. #include "prefs_editor.h"
  37.  
  38.  
  39. // Global variables
  40. static GtkWidget *win;                // Preferences window
  41. static bool start_clicked = true;    // Return value of PrefsEditor() function
  42.  
  43.  
  44. // Prototypes
  45. static void create_volumes_pane(GtkWidget *top);
  46. static void create_scsi_pane(GtkWidget *top);
  47. static void create_graphics_pane(GtkWidget *top);
  48. static void create_input_pane(GtkWidget *top);
  49. static void create_serial_pane(GtkWidget *top);
  50. static void create_memory_pane(GtkWidget *top);
  51. static void read_settings(void);
  52.  
  53.  
  54. /*
  55.  *  Utility functions
  56.  */
  57.  
  58. struct opt_desc {
  59.     int label_id;
  60.     GtkSignalFunc func;
  61. };
  62.  
  63. static void add_menu_item(GtkWidget *menu, int label_id, GtkSignalFunc func)
  64. {
  65.     GtkWidget *item = gtk_menu_item_new_with_label(GetString(label_id));
  66.     gtk_widget_show(item);
  67.     gtk_signal_connect(GTK_OBJECT(item), "activate", func, NULL);
  68.     gtk_menu_append(GTK_MENU(menu), item);
  69. }
  70.  
  71. static GtkWidget *make_pane(GtkWidget *notebook, int title_id)
  72. {
  73.     GtkWidget *frame, *label, *box;
  74.  
  75.     frame = gtk_frame_new(NULL);
  76.     gtk_widget_show(frame);
  77.     gtk_container_border_width(GTK_CONTAINER(frame), 4);
  78.  
  79.     label = gtk_label_new(GetString(title_id));
  80.     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label);
  81.  
  82.     box = gtk_vbox_new(FALSE, 4);
  83.     gtk_widget_show(box);
  84.     gtk_container_set_border_width(GTK_CONTAINER(box), 4);
  85.     gtk_container_add(GTK_CONTAINER(frame), box);
  86.     return box;
  87. }
  88.  
  89. static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *buttons)
  90. {
  91.     GtkWidget *bb, *button;
  92.  
  93.     bb = gtk_hbutton_box_new();
  94.     gtk_widget_show(bb);
  95.     gtk_container_set_border_width(GTK_CONTAINER(bb), border);
  96.     gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_DEFAULT_STYLE);
  97.     gtk_button_box_set_spacing(GTK_BUTTON_BOX(bb), 4);
  98.     gtk_box_pack_start(GTK_BOX(top), bb, FALSE, FALSE, 0);
  99.  
  100.     while (buttons->label_id) {
  101.         button = gtk_button_new_with_label(GetString(buttons->label_id));
  102.         gtk_widget_show(button);
  103.         gtk_signal_connect_object(GTK_OBJECT(button), "clicked", buttons->func, NULL);
  104.         gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0);
  105.         buttons++;
  106.     }
  107.     return bb;
  108. }
  109.  
  110. static GtkWidget *make_separator(GtkWidget *top)
  111. {
  112.     GtkWidget *sep = gtk_hseparator_new();
  113.     gtk_box_pack_start(GTK_BOX(top), sep, FALSE, FALSE, 0);
  114.     gtk_widget_show(sep);
  115.     return sep;
  116. }
  117.  
  118. static GtkWidget *make_table(GtkWidget *top, int x, int y)
  119. {
  120.     GtkWidget *table = gtk_table_new(x, y, FALSE);
  121.     gtk_widget_show(table);
  122.     gtk_box_pack_start(GTK_BOX(top), table, FALSE, FALSE, 0);
  123.     return table;
  124. }
  125.  
  126. static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active)
  127. {
  128.     GtkWidget *box, *label, *opt, *menu;
  129.  
  130.     box = gtk_hbox_new(FALSE, 4);
  131.     gtk_widget_show(box);
  132.     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
  133.  
  134.     label = gtk_label_new(GetString(label_id));
  135.     gtk_widget_show(label);
  136.     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
  137.  
  138.     opt = gtk_option_menu_new();
  139.     gtk_widget_show(opt);
  140.     menu = gtk_menu_new();
  141.  
  142.     while (options->label_id) {
  143.         add_menu_item(menu, options->label_id, options->func);
  144.         options++;
  145.     }
  146.     gtk_menu_set_active(GTK_MENU(menu), active);
  147.  
  148.     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
  149.     gtk_box_pack_start(GTK_BOX(box), opt, FALSE, FALSE, 0);
  150.     return menu;
  151. }
  152.  
  153. static GtkWidget *make_entry(GtkWidget *top, int label_id, const char *prefs_item)
  154. {
  155.     GtkWidget *box, *label, *entry;
  156.  
  157.     box = gtk_hbox_new(FALSE, 4);
  158.     gtk_widget_show(box);
  159.     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
  160.  
  161.     label = gtk_label_new(GetString(label_id));
  162.     gtk_widget_show(label);
  163.     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
  164.  
  165.     entry = gtk_entry_new();
  166.     gtk_widget_show(entry);
  167.     const char *str = PrefsFindString(prefs_item);
  168.     if (str == NULL)
  169.         str = "";
  170.     gtk_entry_set_text(GTK_ENTRY(entry), str); 
  171.     gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
  172.     return entry;
  173. }
  174.  
  175. static GtkWidget *make_checkbox(GtkWidget *top, int label_id, const char *prefs_item, GtkSignalFunc func)
  176. {
  177.     GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id));
  178.     gtk_widget_show(button);
  179.     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), PrefsFindBool(prefs_item));
  180.     gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button);
  181.     gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0);
  182.     return button;
  183. }
  184.  
  185.  
  186. /*
  187.  *  Show preferences editor
  188.  *  Returns true when user clicked on "Start", false otherwise
  189.  */
  190.  
  191. // Window closed
  192. static gint window_closed(void)
  193. {
  194.     return FALSE;
  195. }
  196.  
  197. // Window destroyed
  198. static void window_destroyed(void)
  199. {
  200.     gtk_main_quit();
  201. }
  202.  
  203. // "Start" button clicked
  204. static void cb_start(...)
  205. {
  206.     start_clicked = true;
  207.     read_settings();
  208.     SavePrefs();
  209.     gtk_widget_destroy(win);
  210. }
  211.  
  212. // "Quit" button clicked
  213. static void cb_quit(...)
  214. {
  215.     start_clicked = false;
  216.     gtk_widget_destroy(win);
  217. }
  218.  
  219. // "OK" button of "About" dialog clicked
  220. static void dl_quit(GtkWidget *dialog)
  221. {
  222.     gtk_widget_destroy(dialog);
  223. }
  224.  
  225. // "About" selected
  226. static void mn_about(...)
  227. {
  228.     GtkWidget *dialog, *label, *button;
  229.  
  230.     char str[256];
  231.     sprintf(str, GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
  232.     strncat(str, "\n", 255);
  233.     strncat(str, GetString(STR_ABOUT_TEXT2), 255);
  234.  
  235.     dialog = gtk_dialog_new();
  236.     gtk_widget_set_usize(GTK_WIDGET(dialog), strlen(GetString(STR_ABOUT_TEXT2)) + 200, 120);
  237.     gtk_window_set_title(GTK_WINDOW(dialog), GetString(STR_ABOUT_TITLE));
  238.     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
  239.     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
  240.  
  241.     label = gtk_label_new(str);
  242.     gtk_widget_show(label);
  243.     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
  244.  
  245.     button = gtk_button_new_with_label(GetString(STR_OK_BUTTON));
  246.     gtk_widget_show(button);
  247.     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
  248.     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
  249.     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  250.     gtk_widget_grab_default(button);
  251.     gtk_widget_show(dialog);
  252. }
  253.  
  254. // "Zap PRAM" selected
  255. static void mn_zap_pram(...)
  256. {
  257.     ZapPRAM();
  258. }
  259.  
  260. // Menu item descriptions
  261. static GtkItemFactoryEntry menu_items[] = {
  262.     {(gchar *)GetString(STR_PREFS_MENU_FILE_GTK),        NULL,            NULL,                            0, "<Branch>"},
  263.     {(gchar *)GetString(STR_PREFS_ITEM_START_GTK),        NULL,            GTK_SIGNAL_FUNC(cb_start),        0, NULL},
  264.     {(gchar *)GetString(STR_PREFS_ITEM_ZAP_PRAM_GTK),    NULL,            GTK_SIGNAL_FUNC(mn_zap_pram),    0, NULL},
  265.     {(gchar *)GetString(STR_PREFS_ITEM_SEPL_GTK),        NULL,            NULL,                            0, "<Separator>"},
  266.     {(gchar *)GetString(STR_PREFS_ITEM_QUIT_GTK),        "<control>Q",    GTK_SIGNAL_FUNC(cb_quit),        0, NULL},
  267.     {(gchar *)GetString(STR_HELP_MENU_GTK),                NULL,            NULL,                            0, "<LastBranch>"},
  268.     {(gchar *)GetString(STR_HELP_ITEM_ABOUT_GTK),        NULL,            GTK_SIGNAL_FUNC(mn_about),        0, NULL}
  269. };
  270.  
  271. bool PrefsEditor(void)
  272. {
  273.     // Create window
  274.     win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  275.     gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE));
  276.     gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(window_closed), NULL);
  277.     gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(window_destroyed), NULL);
  278.  
  279.     // Create window contents
  280.     GtkWidget *box = gtk_vbox_new(FALSE, 4);
  281.     gtk_widget_show(box);
  282.     gtk_container_add(GTK_CONTAINER(win), box);
  283.  
  284.     GtkAccelGroup *accel_group = gtk_accel_group_new();
  285.     GtkItemFactory *item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
  286.     gtk_item_factory_create_items(item_factory, sizeof(menu_items) / sizeof(menu_items[0]), menu_items, NULL);
  287.     gtk_accel_group_attach(accel_group, GTK_OBJECT(win));
  288.     GtkWidget *menu_bar = gtk_item_factory_get_widget(item_factory, "<main>");
  289.     gtk_widget_show(menu_bar);
  290.     gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, TRUE, 0);
  291.  
  292.     GtkWidget *notebook = gtk_notebook_new();
  293.     gtk_widget_show(notebook);
  294.     gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
  295.     gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), FALSE);
  296.     gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0);
  297.  
  298.     create_volumes_pane(notebook);
  299.     create_scsi_pane(notebook);
  300.     create_graphics_pane(notebook);
  301.     create_input_pane(notebook);
  302.     create_serial_pane(notebook);
  303.     create_memory_pane(notebook);
  304.  
  305.     static const opt_desc buttons[] = {
  306.         {STR_START_BUTTON, GTK_SIGNAL_FUNC(cb_start)},
  307.         {STR_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)},
  308.         {0, NULL}
  309.     };
  310.     make_button_box(box, 4, buttons);
  311.  
  312.     // Show window and enter main loop
  313.     gtk_widget_show(win);
  314.     gtk_main();
  315.     return start_clicked;
  316. }
  317.  
  318.  
  319. /*
  320.  *  "Volumes" pane
  321.  */
  322.  
  323. static GtkWidget *volume_list, *w_extfs;
  324. static int selected_volume;
  325.  
  326. // Volume in list selected
  327. static void cl_selected(GtkWidget *list, int row, int column)
  328. {
  329.     selected_volume = row;
  330. }
  331.  
  332. struct file_req_assoc {
  333.     file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {}
  334.     GtkWidget *req;
  335.     GtkWidget *entry;
  336. };
  337.  
  338. // Volume selected for addition
  339. static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
  340. {
  341.     char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
  342.     gtk_clist_append(GTK_CLIST(volume_list), &file);
  343.     gtk_widget_destroy(assoc->req);
  344.     delete assoc;
  345. }
  346.  
  347. // Volume selected for creation
  348. static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
  349. {
  350.     char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
  351.  
  352.     char *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
  353.     int size = atoi(str);
  354.  
  355.     char cmd[1024];
  356.     sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", file, size);
  357.     int ret = system(cmd);
  358.     if (ret == 0)
  359.         gtk_clist_append(GTK_CLIST(volume_list), &file);
  360.     gtk_widget_destroy(GTK_WIDGET(assoc->req));
  361.     delete assoc;
  362. }
  363.  
  364. // "Add Volume" button clicked
  365. static void cb_add_volume(...)
  366. {
  367.     GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE));
  368.     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
  369.     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL));
  370.     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
  371.     gtk_widget_show(req);
  372. }
  373.  
  374. // "Create Hardfile" button clicked
  375. static void cb_create_volume(...)
  376. {
  377.     GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE));
  378.  
  379.     GtkWidget *box = gtk_hbox_new(FALSE, 4);
  380.     gtk_widget_show(box);
  381.     GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL));
  382.     gtk_widget_show(label);
  383.     GtkWidget *entry = gtk_entry_new();
  384.     gtk_widget_show(entry);
  385.     char str[32];
  386.     sprintf(str, "%d", 40);
  387.     gtk_entry_set_text(GTK_ENTRY(entry), str);
  388.     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
  389.     gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0);
  390.     gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0);
  391.  
  392.     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
  393.     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry));
  394.     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
  395.     gtk_widget_show(req);
  396. }
  397.  
  398. // "Remove Volume" button clicked
  399. static void cb_remove_volume(...)
  400. {
  401.     gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
  402. }
  403.  
  404. // "Boot From" selected
  405. static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);}
  406. static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);}
  407.  
  408. // "No CD-ROM Driver" button toggled
  409. static void tb_nocdrom(GtkWidget *widget)
  410. {
  411.     PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active);
  412. }
  413.  
  414. // Read settings from widgets and set preferences
  415. static void read_volumes_settings(void)
  416. {
  417.     while (PrefsFindString("disk"))
  418.         PrefsRemoveItem("disk");
  419.  
  420.     for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
  421.         char *str;
  422.         gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
  423.         PrefsAddString("disk", str);
  424.     }
  425.  
  426.     PrefsReplaceString("extfs", gtk_entry_get_text(GTK_ENTRY(w_extfs)));
  427. }
  428.  
  429. // Create "Volumes" pane
  430. static void create_volumes_pane(GtkWidget *top)
  431. {
  432.     GtkWidget *box, *scroll, *menu;
  433.  
  434.     box = make_pane(top, STR_VOLUMES_PANE_TITLE);
  435.  
  436.     scroll = gtk_scrolled_window_new(NULL, NULL);
  437.     gtk_widget_show(scroll);
  438.     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  439.     volume_list = gtk_clist_new(1);
  440.     gtk_widget_show(volume_list);
  441.     gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
  442.     gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
  443.     gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
  444.     gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL);
  445.     char *str;
  446.     int32 index = 0;
  447.     while ((str = (char *)PrefsFindString("disk", index++)) != NULL)
  448.         gtk_clist_append(GTK_CLIST(volume_list), &str);
  449.     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
  450.     gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
  451.     selected_volume = 0;
  452.  
  453.     static const opt_desc buttons[] = {
  454.         {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)},
  455.         {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)},
  456.         {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)},
  457.         {0, NULL},
  458.     };
  459.     make_button_box(box, 0, buttons);
  460.     make_separator(box);
  461.  
  462.     w_extfs = make_entry(box, STR_EXTFS_CTRL, "extfs");
  463.  
  464.     static const opt_desc options[] = {
  465.         {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)},
  466.         {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)},
  467.         {0, NULL}
  468.     };
  469.     int bootdriver = PrefsFindInt32("bootdriver"), active = 0;
  470.     switch (bootdriver) {
  471.         case 0: active = 0; break;
  472.         case CDROMRefNum: active = 1; break;
  473.     }
  474.     menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active);
  475.  
  476.     make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom));
  477. }
  478.  
  479.  
  480. /*
  481.  *  "SCSI" pane
  482.  */
  483.  
  484. static GtkWidget *w_scsi[7];
  485.  
  486. // Read settings from widgets and set preferences
  487. static void read_scsi_settings(void)
  488. {
  489.     for (int id=0; id<7; id++) {
  490.         char prefs_name[32];
  491.         sprintf(prefs_name, "scsi%d", id);
  492.         const char *str = gtk_entry_get_text(GTK_ENTRY(w_scsi[id]));
  493.         if (str && strlen(str))
  494.             PrefsReplaceString(prefs_name, str);
  495.         else
  496.             PrefsRemoveItem(prefs_name);
  497.     }
  498. }
  499.  
  500. // Create "SCSI" pane
  501. static void create_scsi_pane(GtkWidget *top)
  502. {
  503.     GtkWidget *box;
  504.  
  505.     box = make_pane(top, STR_SCSI_PANE_TITLE);
  506.  
  507.     for (int id=0; id<7; id++) {
  508.         char prefs_name[32];
  509.         sprintf(prefs_name, "scsi%d", id);
  510.         w_scsi[id] = make_entry(box, STR_SCSI_ID_0 + id, prefs_name);
  511.     }
  512. }
  513.  
  514.  
  515. /*
  516.  *  "Graphics/Sound" pane
  517.  */
  518.  
  519. // Display types
  520. enum {
  521.     DISPLAY_WINDOW,
  522.     DISPLAY_SCREEN
  523. };
  524.  
  525. static GtkWidget *w_frameskip, *w_display_x, *w_display_y;
  526. static GtkWidget *l_frameskip, *l_display_x, *l_display_y;
  527. static int display_type;
  528. static int dis_width, dis_height;
  529.  
  530. #ifdef ENABLE_FBDEV_DGA
  531. static GtkWidget *w_fbdev_name, *w_fbdevice_file;
  532. static GtkWidget *l_fbdev_name, *l_fbdevice_file;
  533. static char fbdev_name[256];
  534. #endif
  535.  
  536. // Hide/show graphics widgets
  537. static void hide_show_graphics_widgets(void)
  538. {
  539.     switch (display_type) {
  540.         case DISPLAY_WINDOW:
  541.             gtk_widget_show(w_frameskip); gtk_widget_show(l_frameskip);
  542. #ifdef ENABLE_FBDEV_DGA
  543.             gtk_widget_show(w_display_x); gtk_widget_show(l_display_x);
  544.             gtk_widget_show(w_display_y); gtk_widget_show(l_display_y);
  545.             gtk_widget_hide(w_fbdev_name); gtk_widget_hide(l_fbdev_name);
  546. #endif
  547.             break;
  548.         case DISPLAY_SCREEN:
  549.             gtk_widget_hide(w_frameskip); gtk_widget_hide(l_frameskip);
  550. #ifdef ENABLE_FBDEV_DGA
  551.             gtk_widget_hide(w_display_x); gtk_widget_hide(l_display_x);
  552.             gtk_widget_hide(w_display_y); gtk_widget_hide(l_display_y);
  553.             gtk_widget_show(w_fbdev_name); gtk_widget_show(l_fbdev_name);
  554. #endif
  555.             break;
  556.     }
  557. }
  558.  
  559. // "Window" video type selected
  560. static void mn_window(...)
  561. {
  562.     display_type = DISPLAY_WINDOW;
  563.     hide_show_graphics_widgets();
  564. }
  565.  
  566. // "Fullscreen" video type selected
  567. static void mn_fullscreen(...)
  568. {
  569.     display_type = DISPLAY_SCREEN;
  570.     hide_show_graphics_widgets();
  571. }
  572.  
  573. // "5 Hz".."60Hz" selected
  574. static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
  575. static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
  576. static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
  577. static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
  578. static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
  579. static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
  580. static void mn_dynamic(...) {PrefsReplaceInt32("frameskip", 0);}
  581.  
  582. // "Disable Sound Output" button toggled
  583. static void tb_nosound(GtkWidget *widget)
  584. {
  585.     PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
  586. }
  587.  
  588. // Read graphics preferences
  589. static void parse_graphics_prefs(void)
  590. {
  591.     display_type = DISPLAY_WINDOW;
  592.     dis_width = 512;
  593.     dis_height = 384;
  594. #ifdef ENABLE_FBDEV_DGA
  595.     fbdev_name[0] = 0;
  596. #endif
  597.  
  598.     const char *str = PrefsFindString("screen");
  599.     if (str) {
  600.         if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
  601.             display_type = DISPLAY_WINDOW;
  602. #ifdef ENABLE_FBDEV_DGA
  603.         else if (sscanf(str, "dga/%255s", fbdev_name) == 1)
  604. #else
  605.         else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2)
  606. #endif
  607.             display_type = DISPLAY_SCREEN;
  608.     }
  609. }
  610.  
  611. // Read settings from widgets and set preferences
  612. static void read_graphics_settings(void)
  613. {
  614.     const char *str;
  615.  
  616.     str = gtk_entry_get_text(GTK_ENTRY(w_display_x));
  617.     dis_width = atoi(str);
  618.  
  619.     str = gtk_entry_get_text(GTK_ENTRY(w_display_y));
  620.     dis_height = atoi(str);
  621.  
  622.     char pref[256];
  623.     switch (display_type) {
  624.         case DISPLAY_WINDOW:
  625.             sprintf(pref, "win/%d/%d", dis_width, dis_height);
  626.             break;
  627.         case DISPLAY_SCREEN:
  628. #ifdef ENABLE_FBDEV_DGA
  629.             str = gtk_entry_get_text(GTK_ENTRY(w_fbdev_name));
  630.             sprintf(pref, "dga/%s", str);
  631. #else
  632.             sprintf(pref, "dga/%d/%d", dis_width, dis_height);
  633. #endif
  634.             break;
  635.         default:
  636.             PrefsRemoveItem("screen");
  637.             return;
  638.     }
  639.     PrefsReplaceString("screen", pref);
  640. }
  641.  
  642. // Create "Graphics/Sound" pane
  643. static void create_graphics_pane(GtkWidget *top)
  644. {
  645.     GtkWidget *box, *table, *label, *opt, *menu, *combo;
  646.     char str[32];
  647.  
  648.     parse_graphics_prefs();
  649.  
  650.     box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
  651.     table = make_table(box, 2, 5);
  652.  
  653.     label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL));
  654.     gtk_widget_show(label);
  655.     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
  656.  
  657.     opt = gtk_option_menu_new();
  658.     gtk_widget_show(opt);
  659.     menu = gtk_menu_new();
  660.     add_menu_item(menu, STR_WINDOW_LAB, GTK_SIGNAL_FUNC(mn_window));
  661.     add_menu_item(menu, STR_FULLSCREEN_LAB, GTK_SIGNAL_FUNC(mn_fullscreen));
  662.     switch (display_type) {
  663.         case DISPLAY_WINDOW:
  664.             gtk_menu_set_active(GTK_MENU(menu), 0);
  665.             break;
  666.         case DISPLAY_SCREEN:
  667.             gtk_menu_set_active(GTK_MENU(menu), 1);
  668.             break;
  669.     }
  670.     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
  671.     gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
  672.  
  673.     l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL));
  674.     gtk_widget_show(l_frameskip);
  675.     gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
  676.  
  677.     w_frameskip = gtk_option_menu_new();
  678.     gtk_widget_show(w_frameskip);
  679.     menu = gtk_menu_new();
  680.     add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz));
  681.     add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz));
  682.     add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz));
  683.     add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz));
  684.     add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz));
  685.     add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz));
  686.     add_menu_item(menu, STR_REF_DYNAMIC_LAB, GTK_SIGNAL_FUNC(mn_dynamic));
  687.     int frameskip = PrefsFindInt32("frameskip");
  688.     int item = -1;
  689.     switch (frameskip) {
  690.         case 12: item = 0; break;
  691.         case 8: item = 1; break;
  692.         case 6: item = 2; break;
  693.         case 4: item = 3; break;
  694.         case 2: item = 4; break;
  695.         case 1: item = 5; break;
  696.         case 0: item = 6; break;
  697.     }
  698.     if (item >= 0)
  699.         gtk_menu_set_active(GTK_MENU(menu), item);
  700.     gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu);
  701.     gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
  702.  
  703.     l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL));
  704.     gtk_widget_show(l_display_x);
  705.     gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
  706.  
  707.     combo = gtk_combo_new();
  708.     gtk_widget_show(combo);
  709.     GList *glist1 = NULL;
  710.     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB));
  711.     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB));
  712.     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB));
  713.     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB));
  714.     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB));
  715.     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1);
  716.     if (dis_width)
  717.         sprintf(str, "%d", dis_width);
  718.     else
  719.         strcpy(str, GetString(STR_SIZE_MAX_LAB));
  720.     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); 
  721.     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
  722.     w_display_x = GTK_COMBO(combo)->entry;
  723.  
  724.     l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL));
  725.     gtk_widget_show(l_display_y);
  726.     gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
  727.  
  728.     combo = gtk_combo_new();
  729.     gtk_widget_show(combo);
  730.     GList *glist2 = NULL;
  731.     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB));
  732.     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB));
  733.     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB));
  734.     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB));
  735.     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB));
  736.     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2);
  737.     if (dis_height)
  738.         sprintf(str, "%d", dis_height);
  739.     else
  740.         strcpy(str, GetString(STR_SIZE_MAX_LAB));
  741.     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); 
  742.     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
  743.     w_display_y = GTK_COMBO(combo)->entry;
  744.  
  745. #ifdef ENABLE_FBDEV_DGA
  746.     l_fbdev_name = gtk_label_new(GetString(STR_FBDEV_NAME_CTRL));
  747.     gtk_widget_show(l_fbdev_name);
  748.     gtk_table_attach(GTK_TABLE(table), l_fbdev_name, 0, 1, 4, 5, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
  749.  
  750.     w_fbdev_name = gtk_entry_new();
  751.     gtk_widget_show(w_fbdev_name);
  752.     gtk_entry_set_text(GTK_ENTRY(w_fbdev_name), fbdev_name); 
  753.     gtk_table_attach(GTK_TABLE(table), w_fbdev_name, 1, 2, 4, 5, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
  754.  
  755.     w_fbdevice_file = make_entry(box, STR_FBDEVICE_FILE_CTRL, "fbdevicefile");
  756. #endif
  757.  
  758.     make_separator(box);
  759.     make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
  760.  
  761.     hide_show_graphics_widgets();
  762. }
  763.  
  764.  
  765. /*
  766.  *  "Input" pane
  767.  */
  768.  
  769. static GtkWidget *w_keycode_file;
  770. static GtkWidget *w_mouse_wheel_lines;
  771.  
  772. // Set sensitivity of widgets
  773. static void set_input_sensitive(void)
  774. {
  775.     gtk_widget_set_sensitive(w_keycode_file, PrefsFindBool("keycodes"));
  776.     gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
  777. }
  778.  
  779. // "Use Raw Keycodes" button toggled
  780. static void tb_keycodes(GtkWidget *widget)
  781. {
  782.     PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
  783.     set_input_sensitive();
  784. }
  785.  
  786. // "Mouse Wheel Mode" selected
  787. static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
  788. static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
  789.  
  790. // Read settings from widgets and set preferences
  791. static void read_input_settings(void)
  792. {
  793.     const char *str = gtk_entry_get_text(GTK_ENTRY(w_keycode_file));
  794.     if (str && strlen(str))
  795.         PrefsReplaceString("keycodefile", str);
  796.     else
  797.         PrefsRemoveItem("keycodefile");
  798.  
  799.     PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
  800. }
  801.  
  802. // Create "Input" pane
  803. static void create_input_pane(GtkWidget *top)
  804. {
  805.     GtkWidget *box, *hbox, *menu, *label;
  806.     GtkObject *adj;
  807.  
  808.     box = make_pane(top, STR_INPUT_PANE_TITLE);
  809.  
  810.     make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
  811.     w_keycode_file = make_entry(box, STR_KEYCODE_FILE_CTRL, "keycodefile");
  812.  
  813.     make_separator(box);
  814.  
  815.     static const opt_desc options[] = {
  816.         {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
  817.         {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
  818.         {0, NULL}
  819.     };
  820.     int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
  821.     switch (wheelmode) {
  822.         case 0: active = 0; break;
  823.         case 1: active = 1; break;
  824.     }
  825.     menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
  826.  
  827.     hbox = gtk_hbox_new(FALSE, 4);
  828.     gtk_widget_show(hbox);
  829.     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
  830.  
  831.     label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
  832.     gtk_widget_show(label);
  833.     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
  834.  
  835.     adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
  836.     w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
  837.     gtk_widget_show(w_mouse_wheel_lines);
  838.     gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
  839.  
  840.     set_input_sensitive();
  841. }
  842.  
  843.  
  844. /*
  845.  *  "Serial/Network" pane
  846.  */
  847.  
  848. static GtkWidget *w_seriala, *w_serialb, *w_ether;
  849.  
  850. // Read settings from widgets and set preferences
  851. static void read_serial_settings(void)
  852. {
  853.     const char *str;
  854.  
  855.     str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
  856.     PrefsReplaceString("seriala", str);
  857.  
  858.     str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
  859.     PrefsReplaceString("serialb", str);
  860.  
  861.     str = gtk_entry_get_text(GTK_ENTRY(w_ether));
  862.     if (str && strlen(str))
  863.         PrefsReplaceString("ether", str);
  864.     else
  865.         PrefsRemoveItem("ether");
  866. }
  867.  
  868. // Add names of serial devices
  869. static gint gl_str_cmp(gconstpointer a, gconstpointer b)
  870. {
  871.     return strcmp((char *)a, (char *)b);
  872. }
  873.  
  874. static GList *add_serial_names(void)
  875. {
  876.     GList *glist = NULL;
  877.  
  878.     // Search /dev for ttyS* and lp*
  879.     DIR *d = opendir("/dev");
  880.     if (d) {
  881.         struct dirent *de;
  882.         while ((de = readdir(d)) != NULL) {
  883. #if defined(__linux__)
  884.             if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) {
  885. #elif defined(__FreeBSD__)
  886.             if (strncmp(de->d_name, "cuaa", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
  887. #elif defined(__NetBSD__)
  888.             if (strncmp(de->d_name, "tty0", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
  889. #elif defined(sgi)
  890.             if (strncmp(de->d_name, "ttyf", 4) == 0 || strncmp(de->d_name, "plp", 3) == 0) {
  891. #else
  892.             if (false) {
  893. #endif
  894.                 char *str = new char[64];
  895.                 sprintf(str, "/dev/%s", de->d_name);
  896.                 glist = g_list_append(glist, str);
  897.             }
  898.         }
  899.         closedir(d);
  900.     }
  901.     if (glist)
  902.         g_list_sort(glist, gl_str_cmp);
  903.     else
  904.         glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
  905.     return glist;
  906. }
  907.  
  908. // Add names of ethernet interfaces
  909. static GList *add_ether_names(void)
  910. {
  911.     GList *glist = NULL;
  912.  
  913.     // Get list of all Ethernet interfaces
  914.     int s = socket(PF_INET, SOCK_DGRAM, 0);
  915.     if (s >= 0) {
  916.         char inbuf[8192];
  917.         struct ifconf ifc;
  918.         ifc.ifc_len = sizeof(inbuf);
  919.         ifc.ifc_buf = inbuf;
  920.         if (ioctl(s, SIOCGIFCONF, &ifc) == 0) {
  921.             struct ifreq req, *ifr = ifc.ifc_req;
  922.             for (int i=0; i<ifc.ifc_len; i+=sizeof(ifreq), ifr++) {
  923.                 req = *ifr;
  924. #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(sgi)
  925.                 if (ioctl(s, SIOCGIFADDR, &req) == 0 && (req.ifr_addr.sa_family == ARPHRD_ETHER || req.ifr_addr.sa_family == ARPHRD_ETHER+1)) {
  926. #elif defined(__linux__)
  927.                 if (ioctl(s, SIOCGIFHWADDR, &req) == 0 && req.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
  928. #else
  929.                 if (false) {
  930. #endif
  931.                     char *str = new char[64];
  932.                     strncpy(str, ifr->ifr_name, 63);
  933.                     glist = g_list_append(glist, str);
  934.                 }
  935.             }
  936.         }
  937.         close(s);
  938.     }
  939.     if (glist)
  940.         g_list_sort(glist, gl_str_cmp);
  941.     else
  942.         glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
  943.     return glist;
  944. }
  945.  
  946. // Create "Serial/Network" pane
  947. static void create_serial_pane(GtkWidget *top)
  948. {
  949.     GtkWidget *box, *table, *label, *combo, *sep;
  950.     GList *glist = add_serial_names();
  951.  
  952.     box = make_pane(top, STR_SERIAL_NETWORK_PANE_TITLE);
  953.     table = make_table(box, 2, 4);
  954.  
  955.     label = gtk_label_new(GetString(STR_SERIALA_CTRL));
  956.     gtk_widget_show(label);
  957.     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
  958.  
  959.     combo = gtk_combo_new();
  960.     gtk_widget_show(combo);
  961.     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
  962.     const char *str = PrefsFindString("seriala");
  963.     if (str == NULL)
  964.         str = "";
  965.     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); 
  966.     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
  967.     w_seriala = GTK_COMBO(combo)->entry;
  968.  
  969.     label = gtk_label_new(GetString(STR_SERIALB_CTRL));
  970.     gtk_widget_show(label);
  971.     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
  972.  
  973.     combo = gtk_combo_new();
  974.     gtk_widget_show(combo);
  975.     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
  976.     str = PrefsFindString("serialb");
  977.     if (str == NULL)
  978.         str = "";
  979.     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); 
  980.     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
  981.     w_serialb = GTK_COMBO(combo)->entry;
  982.  
  983.     sep = gtk_hseparator_new();
  984.     gtk_widget_show(sep);
  985.     gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
  986.  
  987.     label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
  988.     gtk_widget_show(label);
  989.     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
  990.  
  991.     glist = add_ether_names();
  992.     combo = gtk_combo_new();
  993.     gtk_widget_show(combo);
  994.     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
  995.     str = PrefsFindString("ether");
  996.     if (str == NULL)
  997.         str = "";
  998.     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); 
  999.     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
  1000.     w_ether = GTK_COMBO(combo)->entry;
  1001. }
  1002.  
  1003.  
  1004. /*
  1005.  *  "Memory/Misc" pane
  1006.  */
  1007.  
  1008. static GtkObject *w_ramsize_adj;
  1009. static GtkWidget *w_rom_file;
  1010.  
  1011. // Model ID selected
  1012. static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);}
  1013. static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);}
  1014.  
  1015. // CPU/FPU type
  1016. static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);}
  1017. static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);}
  1018. static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);}
  1019. static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);}
  1020. static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);}
  1021.  
  1022. // Read settings from widgets and set preferences
  1023. static void read_memory_settings(void)
  1024. {
  1025.     PrefsReplaceInt32("ramsize", int(GTK_ADJUSTMENT(w_ramsize_adj)->value) << 20);
  1026.  
  1027.     const char *str = gtk_entry_get_text(GTK_ENTRY(w_rom_file));
  1028.     if (str && strlen(str))
  1029.         PrefsReplaceString("rom", str);
  1030.     else
  1031.         PrefsRemoveItem("rom");
  1032.  
  1033. }
  1034.  
  1035. // Create "Memory/Misc" pane
  1036. static void create_memory_pane(GtkWidget *top)
  1037. {
  1038.     GtkWidget *box, *hbox, *vbox, *hbox2, *label, *scale, *menu;
  1039.  
  1040.     box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
  1041.  
  1042.     hbox = gtk_hbox_new(FALSE, 4);
  1043.     gtk_widget_show(hbox);
  1044.  
  1045.     label = gtk_label_new(GetString(STR_RAMSIZE_SLIDER));
  1046.     gtk_widget_show(label);
  1047.     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
  1048.  
  1049.     vbox = gtk_vbox_new(FALSE, 4);
  1050.     gtk_widget_show(vbox);
  1051.  
  1052.     gfloat min, max;
  1053.     min = 1;
  1054.     max = 1024;
  1055.     w_ramsize_adj = gtk_adjustment_new(min, min, max, 1, 16, 0);
  1056.     gtk_adjustment_set_value(GTK_ADJUSTMENT(w_ramsize_adj), PrefsFindInt32("ramsize") >> 20);
  1057.  
  1058.     scale = gtk_hscale_new(GTK_ADJUSTMENT(w_ramsize_adj));
  1059.     gtk_widget_show(scale);
  1060.     gtk_scale_set_digits(GTK_SCALE(scale), 0);
  1061.     gtk_box_pack_start(GTK_BOX(vbox), scale, TRUE, TRUE, 0);
  1062.  
  1063.     hbox2 = gtk_hbox_new(FALSE, 4);
  1064.     gtk_widget_show(hbox2);
  1065.  
  1066.     char val[32];
  1067.     sprintf(val, GetString(STR_RAMSIZE_FMT), int(min));
  1068.     label = gtk_label_new(val);
  1069.     gtk_widget_show(label);
  1070.     gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
  1071.  
  1072.     sprintf(val, GetString(STR_RAMSIZE_FMT), int(max));
  1073.     label = gtk_label_new(val);
  1074.     gtk_widget_show(label);
  1075.     gtk_box_pack_end(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
  1076.     gtk_box_pack_start(GTK_BOX(vbox), hbox2, TRUE, TRUE, 0);
  1077.     gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
  1078.     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
  1079.  
  1080.     static const opt_desc model_options[] = {
  1081.         {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
  1082.         {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)},
  1083.         {0, NULL}
  1084.     };
  1085.     int modelid = PrefsFindInt32("modelid"), active = 0;
  1086.     switch (modelid) {
  1087.         case 5: active = 0; break;
  1088.         case 14: active = 1; break;
  1089.     }
  1090.     make_option_menu(box, STR_MODELID_CTRL, model_options, active);
  1091.  
  1092. #if EMULATED_68K
  1093.     static const opt_desc cpu_options[] = {
  1094.         {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)},
  1095.         {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)},
  1096.         {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)},
  1097.         {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)},
  1098.         {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)},
  1099.         {0, NULL}
  1100.     };
  1101.     int cpu = PrefsFindInt32("cpu");
  1102.     bool fpu = PrefsFindBool("fpu");
  1103.     active = 0;
  1104.     switch (cpu) {
  1105.         case 2: active = fpu ? 1 : 0; break;
  1106.         case 3: active = fpu ? 3 : 2; break;
  1107.         case 4: active = 4;
  1108.     }
  1109.     make_option_menu(box, STR_CPU_CTRL, cpu_options, active);
  1110. #endif
  1111.  
  1112.     w_rom_file = make_entry(box, STR_ROM_FILE_CTRL, "rom");
  1113. }
  1114.  
  1115.  
  1116. /*
  1117.  *  Read settings from widgets and set preferences
  1118.  */
  1119.  
  1120. static void read_settings(void)
  1121. {
  1122.     read_volumes_settings();
  1123.     read_scsi_settings();
  1124.     read_graphics_settings();
  1125.     read_input_settings();
  1126.     read_serial_settings();
  1127.     read_memory_settings();
  1128. }
  1129.